/*
 *
 * Author: Allan <qimingos_lsk@163.com>, (C) 2005-2007
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
 *
 */
#include "include/ShowLyric.h"
#include "include/EditLyricDlg.h"
#include "include/ShowLyricDlg.h"
#include "include/ManualDownLoadDlg.h"
#include "include/ConfigDlg.h"
#include <cairo.h>

#define EDIT_LYRIC_GLADE_FILE "/usr/share/ShowLyric/EditLyricDlg.glade"

static gboolean on_expose_event (GtkWidget * widget, GdkEventExpose * event, gpointer data)
{
	ShowLyric();
	return FALSE;
}

GtkWidget * CreateShowLyricDlg()
{
	GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);

	gtk_widget_set_events(window, GDK_ALL_EVENTS_MASK);

	CONNECT_SIGNAL(G_OBJECT (window), expose-event, on_expose_event, NULL);
	CONNECT_SIGNAL(G_OBJECT (window), window-state-event, on_ShowLyric_window_state_event, window);
	CONNECT_SIGNAL(G_OBJECT (window), delete-event, on_ShowLyric_delete_event, NULL);
	CONNECT_SIGNAL(G_OBJECT (window), button-press-event, on_ShowLyric_button_press_event, NULL);
	CONNECT_SIGNAL(G_OBJECT (window), scroll-event, on_ShowLyric_scroll_event, NULL);
	CONNECT_SIGNAL(G_OBJECT (window), motion-notify-event, on_ShowLyric_motion_notify_event, NULL);

    gtk_window_set_position (GTK_WINDOW (window),
                             GTK_WIN_POS_CENTER);

    gtk_window_set_default_size (GTK_WINDOW (window), 120, 180);
    gtk_window_set_title (GTK_WINDOW (window), PLUGIN_NAME);

    gtk_widget_set_app_paintable (window, TRUE);
	gtk_window_set_opacity(GTK_WINDOW(window), 1 - theApp.m_configs.iOpacity / 100.0);
	gtk_window_set_decorated(GTK_WINDOW(window), theApp.m_configs.bShowBroad);
    gtk_widget_show_all (window);
    return window;
}

#define this  theApp.m_LyricWnd
void LyricWndInit()
{
	this.ShowLyric = ShowLyric;
	this.ParseLyric = ParseLyric;
	this.SmartShowWnd = SmartShowWnd;
	this.ClearLyric = ClearLyric;
	this.RefreshLyricSetting = RefreshLyricSetting;
	this.m_TimerId = 0;
	this._m_current = NULL;
	this.m_ListCurrLyric = NULL;
	this.m_bScrollMouseChange = FALSE;
	this.m_bLyricChanged = FALSE;
	this.m_bLyricChanging = FALSE;
	theApp.m_LyricWnd.pThis = CreateShowLyricDlg();

	gtk_window_set_keep_above(GTK_WINDOW(theApp.m_LyricWnd.pThis), TRUE);

	gtk_window_move(GTK_WINDOW(theApp.m_LyricWnd.pThis), theApp.m_configs.pos.iX,
			theApp.m_configs.pos.iY);

	XML_CONNECT_SIGNAL2(theApp.m_xml, on_MenuEditLyric_activate, theApp.m_LyricWnd.pThis);
	XML_CONNECT_SIGNAL2(theApp.m_xml, on_MenuReDownLoad_activate, theApp.m_LyricWnd.pThis);
	XML_CONNECT_SIGNAL2(theApp.m_xml, on_MenuConfig_activate, theApp.m_LyricWnd.pThis);
	XML_CONNECT_SIGNAL2(theApp.m_xml, on_MenuAbout_activate, theApp.m_LyricWnd.pThis);
	XML_CONNECT_SIGNAL2(theApp.m_xml, on_MenuUpTime_activate, theApp.m_LyricWnd.pThis);
	XML_CONNECT_SIGNAL2(theApp.m_xml, on_MenuDownTime_activate, theApp.m_LyricWnd.pThis);
	XML_CONNECT_SIGNAL2(theApp.m_xml, on_MenuMouseScroll_toggled, theApp.m_LyricWnd.pThis);
	XML_CONNECT_SIGNAL2(theApp.m_xml, on_MenuShowBroad_toggled, theApp.m_LyricWnd.pThis);
	XML_CONNECT_SIGNAL2(theApp.m_xml, on_MenuShowOSD_toggled, theApp.m_LyricWnd.pThis);
	XML_CONNECT_SIGNAL2(theApp.m_xml, on_MenuKaLaOK_toggled, theApp.m_LyricWnd.pThis);
	XML_CONNECT_SIGNAL2(theApp.m_xml, on_MenuManualDownLoad_activate, theApp.m_LyricWnd.pThis);

	this.m_EditLyricDlg.m_pEditLyricXML = glade_xml_new(EDIT_LYRIC_GLADE_FILE, NULL, NULL);
	EditLyricDlgInit();
	SmartShowWnd(TRUE);
}

// 将字符串“00:12.123”转化为数字
int _GetTime(gchar* lpszTime)
{
	int iMS = 0, iSec = 0, iMinute = 0;
	gchar* lpszTmp= NULL;
	int iBegin = StrLeftFind(lpszTime, 0, '.');
	if (iBegin >= 0)
	{
		lpszTmp = lpszTime + iBegin;
		*lpszTmp = 0;
		lpszTmp++;
		iMS = atoi(lpszTmp);
	}
	iBegin = StrLeftFind(lpszTime, 0, ':');
	if (iBegin >= 0)
	{
		lpszTmp = lpszTime + iBegin;
		*lpszTmp = 0;
		lpszTmp++;
		iSec = atoi(lpszTmp);
	}
	iMinute = atoi(lpszTime);
	return (iMinute * 60 + iSec) * 1000 + iMS;
}

void _ClearList()
{
	g_assert(!this.m_bLyricChanging);
	// TODO: 保存修改后的歌词
	GList *list= this.m_ListCurrLyric;
	GList* OldList = list;
	this.m_ListCurrLyric = NULL;
	this._m_current = NULL;
	if (OldList)
	{
		gtk_timeout_remove(this.m_TimerId);
		usleep(500);
	}
	while (list)
	{
		LyricItem *item = (LyricItem *) list->data;
		if (item)
		{
			if (item->lpszValue)g_free(item->lpszValue);
			g_free(item);
		}
		list = g_list_next(list);
	}
	g_list_free(OldList);
}

// 将一个时间点的歌词加入到链表里面去
void _ParseLine(int iTime, gchar* lpszValue)
{
	GList* list = g_list_first(this.m_ListCurrLyric);
	LyricItem *pNewItem = (LyricItem *)g_malloc0(sizeof(LyricItem));
	pNewItem->iTime = iTime;
	pNewItem->lpszValue = (gchar *)g_malloc0(strlen(lpszValue) + 1);
	strcpy(pNewItem->lpszValue, lpszValue);
	gchar* pWork = pNewItem->lpszValue;
	while (*pWork != 0)
	{
		if (*pWork == '\r' || *pWork == '\n')
			*pWork = '\0';
		pWork++;
	}
	while (list)
	{
		LyricItem* lpItem = list->data;
		if (lpItem->iTime > iTime)
		{
			this.m_ListCurrLyric = g_list_insert_before(this.m_ListCurrLyric,
					list, pNewItem);
			return;
		}
		list = g_list_next(list);
	}
	this.m_ListCurrLyric = g_list_append(this.m_ListCurrLyric, pNewItem);
}

// 解析歌词
gboolean ParseLyric(gchar* lpszLyricFileName)
{
	_ClearList();
	FILE * pLyricFile = fopen(lpszLyricFileName, "r");
	if (!pLyricFile)
	{
		LyricLog("加载歌词文件%s失败", lpszLyricFileName);
		theApp.m_LyricWnd.SmartShowWnd(FALSE);
		return FALSE;
	}
	gchar szBuf[512] =
	{ 0 };

	if (!fgets(szBuf, 512, pLyricFile))
	{
		return FALSE;
	}
	fseek(pLyricFile, 0, SEEK_END);
	int iLen = ftell(pLyricFile);
	fseek(pLyricFile, 0, SEEK_SET);
	gchar * lpszLine = (gchar *)g_malloc(iLen);
	while (fgets(lpszLine, iLen, pLyricFile) != NULL)
	{
		int iEnd = StrLeftFind(lpszLine, 0, ']');
		if (iEnd > 0)
		{
			gchar* lpszValue = lpszLine + iEnd;
			*lpszValue = 0;
			lpszValue++;
			gchar* lpszTimes = lpszLine;
			int iBegin = StrLeftFind(lpszTimes, 0, '[');
			while (iBegin >= 0)
			{
				gchar* lpszTime = lpszTimes + iBegin;
				*lpszTime = 0;
				lpszTime++;
				if (lpszTime[strlen(lpszTime) - 1] == ']')
					lpszTime[strlen(lpszTime) - 1] = 0;
				// 转换时间pTime为iTime
				int iTime = _GetTime(lpszTime);

				gchar * lpszUTF8 = theApp.m_player.Str2UTF8(lpszValue);
				if (lpszUTF8)
				{
					_ParseLine(iTime, lpszUTF8);
					g_free(lpszUTF8);
					lpszUTF8 = NULL;
				}
				else
				{
					_ParseLine(iTime, lpszValue);
				}
				iBegin = StrLeftFind(lpszTimes, 0, '[');
			}
		}
	}

	fclose(pLyricFile);
	pLyricFile = NULL;
	g_free(lpszLine);
	lpszLine = NULL;

	if (g_list_length(this.m_ListCurrLyric) > 0)
	{
		ShowLyric();
	}
	return TRUE;
}

void ClearLyric()
{
	this.m_bLyricChanging = FALSE;
	this.m_bLyricChanged = FALSE;
	_ClearList();

	if (theApp.m_configs.bShowOSDLyric)
	{
		if (system("gnome-osd-client -f \"<message id='ShowLyric' hide_timeout='0'></message>\"") < 0)
		{
			LyricLog("Exec gnome-osd-client failed!");
		}
	}
}

void SmartShowWnd(gboolean bShow)
{
	GtkWidget * pEditLyricDlg = glade_xml_get_widget(
	this.m_EditLyricDlg.m_pEditLyricXML,
	"EditLyricDlg");
	if (this.m_EditLyricDlg.m_bEditing)
	{
		gtk_widget_show(pEditLyricDlg);
		gtk_widget_hide(theApp.m_LyricWnd.pThis);
		return;
	}
	else
	{
		gtk_widget_hide(pEditLyricDlg);
	}
	if (!theApp.m_configs.bShowWindowLyric)
	{
		gtk_widget_hide(theApp.m_LyricWnd.pThis);
		return;
	}

	if (!theApp.m_configs.bSmartShowWin)return;

	if (bShow)
	{
		if (!gtk_widget_get_visible(theApp.m_LyricWnd.pThis))
		{
			gtk_window_set_keep_above(GTK_WINDOW(theApp.m_LyricWnd.pThis), TRUE);
			gtk_window_move(GTK_WINDOW(theApp.m_LyricWnd.pThis), theApp.m_configs.pos.iX,
					theApp.m_configs.pos.iY);
			gtk_widget_show(theApp.m_LyricWnd.pThis);
		}
	}
	else
	{
		gtk_widget_hide(theApp.m_LyricWnd.pThis);
	}
}

gboolean ScrollLyric(gpointer data)
{
	ShowLyric();
	return TRUE;
}

inline gint number_between(gint from, gint to, gdouble rate)
{
	return (rate<1.0)?from + rate * (to - from):to;
}

void color_between(GdkColor * from, GdkColor * to, gdouble rate,
		GdkColor * result)
{
	if (!from || !to || !result)
		return;
	result->pixel = number_between(from->pixel, to->pixel, rate);
	result->red = number_between(from->red, to->red, rate);
	result->green = number_between(from->green, to->green, rate);
	result->blue = number_between(from->blue, to->blue, rate);
}

inline gboolean IsSmaller(int *piNew)
{
	static int iOldY;
	static int iBuffer; // 如果跳跃太大，多余的跳跃将缓存到该变量中，在后面的移动中慢慢释放出来，以防止跳跃太大
	static int iRate; // 释放缓存的速度

	if (*piNew == 50000)
	{
		iOldY = *piNew;
		iBuffer = 0;
		iRate = 0;
		return TRUE;
	}
	// 如果是后退则直接后退
	if (*piNew > iOldY + 50)
	{
		iOldY = *piNew;
		iBuffer = 0;
		iRate = 0;
		return TRUE;
	}
	// 如果是前进， 则做延缓处理
	if (*piNew < iOldY || (*piNew == iOldY && iBuffer > 0))
	{
		int iTmp = iOldY - *piNew, iFlag = iRate + 1;

		if (iTmp > iFlag && iTmp < 20)
		{
			iBuffer += iOldY - *piNew - iFlag;
			if (iBuffer <= 0)
				iRate = 0;
			else if (iBuffer <= 10)
				iRate = 1;
			else if (iBuffer <= 20)
				iRate = 2;
			else if (iBuffer <= 30)
				iRate = 3;
			else if (iBuffer <= 40)
				iRate = 4;
			else if (iBuffer <= 50)
				iRate = 5;
			else if (iBuffer <= 60)
				iRate = 6;
			else if (iBuffer > 60)
				iRate = 10;
			*piNew = iOldY - iFlag;
		}
		else
		{
			if (iBuffer > 0)
			{
				int iAdd = iRate < iBuffer ? iRate : iBuffer;

				*piNew += iAdd;
				iBuffer -= iAdd;
				if (iBuffer <= 0)
					iRate = 0;
				else if (iBuffer <= 10)
					iRate = 1;
				else if (iBuffer <= 20)
					iRate = 2;
				else if (iBuffer <= 30)
					iRate = 3;
				else if (iBuffer <= 40)
					iRate = 4;
				else if (iBuffer <= 50)
					iRate = 5;
				else if (iBuffer <= 60)
					iRate = 6;
				else if (iBuffer > 60)
					iRate = 10;
				if (iOldY - *piNew < 0)
				{
					iBuffer = iOldY - *piNew;
					*piNew = iOldY;
				}
			}
		}
		// LyricDebug("iY=%d, iBuffer=%d, iRate=%d", iOldY - *piNew, iBuffer, iRate);

		iOldY = *piNew;
		return TRUE;
	}
	return FALSE;
}
gint GetTextWidth(gchar * lpszVal, gint* pHeight, int iFontSize)
{
	if (!theApp.m_LyricWnd.pThis || !gtk_widget_get_visible(theApp.m_LyricWnd.pThis))
		return strlen(lpszVal) * iFontSize;

	cairo_t *cr;
	cr = gdk_cairo_create (theApp.m_LyricWnd.pThis->window);
	cairo_select_font_face (cr, theApp.m_configs.szLyricFontName,
							CAIRO_FONT_SLANT_NORMAL,
							CAIRO_FONT_WEIGHT_NORMAL);
	cairo_set_font_size (cr, iFontSize);
	cairo_text_extents_t extents = {0};
	cairo_text_extents(cr, lpszVal, &extents);
	if (pHeight)
	{
		*pHeight = extents.height;
	}
	cairo_destroy (cr);
	return extents.width;
}

void ShowOSDLyric(gchar * lpszLyric, gint nTime)
{
	if (!theApp.m_configs.bShowOSDLyric)return;

	char szMsg[2048] = {0};

	if (lpszLyric && strlen(lpszLyric))
	{
		snprintf(szMsg, 2048,
				"gnome-osd-client -f \"<message id='ShowLyric' "
				"osd_fake_translucent_bg='%s' "
				"osd_vposition='%s' "
				"animations='%s' "
				"osd_halignment='%s' "
				"osd_font='%s' "
				"hide_timeout='%u'>%s</message>\"",
				theApp.m_configs.OSD.fake_translucent_bg,
				theApp.m_configs.OSD.vposition,
				theApp.m_configs.OSD.animations,
				theApp.m_configs.OSD.halignment,
				theApp.m_configs.OSD.szFontName,
				nTime,
				lpszLyric);
	}
	else
	{
		snprintf(szMsg, 2048,
				"gnome-osd-client -f \"<message id='ShowLyric' "
				"osd_fake_translucent_bg='%s' "
				"osd_vposition='%s' "
				"animations='%s' "
				"osd_halignment='%s' "
				"osd_font='%s' "
				"hide_timeout='%u'>%s</message>\"",
				theApp.m_configs.OSD.fake_translucent_bg,
				theApp.m_configs.OSD.vposition,
				theApp.m_configs.OSD.animations,
				theApp.m_configs.OSD.halignment,
				theApp.m_configs.OSD.szFontName,
				nTime,
				"...");
	}
	if (system(szMsg) < 0)
	{
		LyricLog("Exec CMD(%s) failed!", szMsg);
	}
}

void ShowLyric()
{
	if (!this.m_ListCurrLyric || !theApp.m_LyricWnd.pThis)return;

	gint iWndWidth = 0;
	gtk_widget_set_app_paintable (theApp.m_LyricWnd.pThis, TRUE);
	gint iWndHeight = 0;
	gtk_window_get_size(GTK_WINDOW(theApp.m_LyricWnd.pThis), &iWndWidth, &iWndHeight);
	iWndWidth = 0;
	// 显示歌词
	PangoFontDescription *font_desc =
		pango_font_description_from_string(theApp.m_configs.szLyricFontName);
	int iFontSize = pango_font_description_get_size(font_desc) / PANGO_SCALE;
	pango_font_description_free(font_desc);
	int nCurrLine = -1, nLine = 0;
	const gint nCurrTime = theApp.m_player.GetCurrTime();
	const gint nSongTotalTime = theApp.m_player.GetSongTime();
	gint nCurrLineTimeLen = 0;
	int nPosInLine = 0;
	// 计算窗口宽度和当前需要显示的项
	int iHeight = 0, iCurrHeightInLyric = 0;
	GList* list = g_list_first(this.m_ListCurrLyric);
#define HIGH_SPACE 5
	while (list)
	{
		LyricItem* lpItem = list->data;
		int iTmp = 0;
		int iWidth = GetTextWidth(lpItem->lpszValue, &iTmp, iFontSize) + iFontSize * 4;
		if (nCurrLine == -1)
			iCurrHeightInLyric += iTmp + HIGH_SPACE;
		if (iWidth > iWndWidth)iWndWidth = iWidth;
		gint nNextLineTime = nSongTotalTime;
		if (g_list_next(list))
		{
			nNextLineTime = ((LyricItem*)(g_list_next(list)->data))->iTime;
		}

		if (nCurrTime >= lpItem->iTime &&
			nCurrTime < nNextLineTime)
		{
			iHeight = iTmp;
			nCurrLine = nLine;
			const int nCurrLine_Time = lpItem->iTime;
			nCurrLineTimeLen = nNextLineTime - nCurrLine_Time;
			nPosInLine = (nCurrTime - nCurrLine_Time) * 1000 / (nCurrLineTimeLen);
			static int nOldLine = -1;
			if (nCurrLine != nOldLine)
			{
				nOldLine = nCurrLine;
				ShowOSDLyric(lpItem->lpszValue, nNextLineTime - nCurrLine_Time);
			}
		}
		nLine++;
		list = g_list_next(list);
	}
	SmartShowWnd(TRUE);
	if (!gtk_widget_get_visible(theApp.m_LyricWnd.pThis))return;
	gint nYInLine = (iHeight + HIGH_SPACE) * nPosInLine / 1000;
	gint nY = (iWndHeight / 2) - (iCurrHeightInLyric + nYInLine) + 2 * (iFontSize + HIGH_SPACE);

	// 当变化太大时进行修补
	static gint nOldLine = 0;
	static gint nHistory = 0;
	static gint nOldY = 0;
	if (nOldLine != nCurrLine)
	{
		nOldLine = nCurrLine;
		nHistory = 0;
	}
	if (nOldY - nY > 2 && nOldY - nY < iHeight)
	{
		nHistory = nY - nOldY;
		nY = nOldY;
	}
	if (nHistory)
	{
		int n = 1;
		if (nHistory < 0) n = -1;
		nY = nOldY + n;
		nHistory -= n;
	}
	nOldY = nY;


	if (!theApp.m_configs.bIsKaLaOK)
	{
		static gint nOldY = 0;
		if (nY == nOldY)return;
		nOldY = nY;
	}
	else
	{
		static gint nOld = 0;
		if (nPosInLine == nOld)return;
		nOld = nPosInLine;
	}


	list = g_list_first(this.m_ListCurrLyric);
	BEGIN_SHOW_LYRIC(iFontSize, iWndWidth, iWndHeight, theApp.m_configs.colors.background, theApp.m_configs.szLyricFontName);
	nLine = 0;
	int iY = nY;
	while (list)
	{
		LyricItem* lpItem = list->data;
		int iWidth = GetTextWidth(lpItem->lpszValue, &iHeight, iFontSize);
		gint nNextLineTime = nSongTotalTime;
		if (g_list_next(list))
		{
			nNextLineTime = ((LyricItem*)(g_list_next(list)->data))->iTime;
		}

		const int threshold = 10000;

		GdkColor color;
		if (nLine == nCurrLine)// 当前歌词
		{
			if (!theApp.m_configs.bIsKaLaOK)
			{
				SHOW_LYRIC(iWndWidth, iY, lpItem->lpszValue, theApp.m_configs.colors.current);
			}
			else
			{
				const int nCount = g_utf8_strlen(lpItem->lpszValue, 512);
				const int nxxxValWidth = iWidth;
				gchar * crt = lpItem->lpszValue;
				int i = 0;
				int nPreCharWidth = 0;
				int iX = (iWndWidth - nxxxValWidth) / 2;
				while (*crt && i < nCount)
				{
					int nPos = i * 1000 / nCount;

					const int delta = abs(nPos - nPosInLine);
					if (nPos <= nPosInLine)
					{
						color = theApp.m_configs.colors.current;
					}
					else if (delta <= 200)
					{
						color_between(&theApp.m_configs.colors.current,
								  &theApp.m_configs.colors.normal,
								  (gdouble) delta / 200, &color);
					}
					else
					{
						color = theApp.m_configs.colors.normal;
					}

					gdk_cairo_set_source_color(cr, &theApp.m_configs.colors.background);
					cairo_rectangle (cr, iX, iY - iHeight, nxxxValWidth, iHeight * 2);
					cairo_fill (cr);

					gdk_cairo_set_source_color(cr, &color);
					cairo_move_to (cr, iX, iY);
					cairo_show_text (cr, crt);


					// 计算字符的宽度
					int width1 = GetTextWidth(crt, NULL, iFontSize);
					int width2 = 0;
					if (*g_utf8_next_char (crt))
					{
						width2 = GetTextWidth(g_utf8_next_char (crt), NULL, iFontSize);
					}
					else
					{
						width2 = 0;
					}
					nPreCharWidth = width1 - width2;
					iX += nPreCharWidth;

					crt = g_utf8_next_char (crt);
					i++;
				}
			}
		}
		else
		{
			int delta = abs(lpItem->iTime - nCurrTime);
			if (delta <= threshold && !theApp.m_configs.bIsKaLaOK)
			{
				color_between(&theApp.m_configs.colors.current,
						  &theApp.m_configs.colors.normal,
						  (gdouble) delta / threshold, &color);
			}
			else
			{
				color = theApp.m_configs.colors.normal;
			}
			SHOW_LYRIC(iWndWidth, iY, lpItem->lpszValue, color);
		}
		iY += iHeight + HIGH_SPACE;
		nLine++;
		list = g_list_next(list);
	}
	END_SHOW_LYRIC();

	gtk_window_resize(GTK_WINDOW(theApp.m_LyricWnd.pThis), iWndWidth, iWndHeight);

	static int nXX = 0;
	if (nXX != 12345)
	{
		nXX = 12345;
		g_timeout_add(100, ScrollLyric, NULL);
	}
}

void OnShowState(const gchar * format, ...)
{
	SmartShowWnd(TRUE);
	if (this.m_ListCurrLyric || !theApp.m_LyricWnd.pThis)return;
	if (!gtk_widget_get_visible(theApp.m_LyricWnd.pThis))return;

	va_list args;
	gchar szBuf[512] =
	{ 0 };
	va_start(args, format);
	vsnprintf(szBuf, 511, format, args);
	va_end(args);

	int iFontSize = 14;
	gint iWndHeight = 0, iWndWidth = 0, iTxtWidth = 0;
	iTxtWidth = GetTextWidth(szBuf, NULL, iFontSize);
	gtk_window_get_size(GTK_WINDOW(theApp.m_LyricWnd.pThis), &iWndWidth, &iWndHeight);
	iWndWidth = iTxtWidth + iFontSize * 2;
	gtk_window_resize(GTK_WINDOW(theApp.m_LyricWnd.pThis), iWndWidth, iWndHeight);
	BEGIN_SHOW_LYRIC(iFontSize, iWndWidth, iWndHeight, theApp.m_configs.colors.background, theApp.m_configs.szLyricFontName);
	SHOW_LYRIC(iWndWidth, iWndHeight / 2 - 7, szBuf, theApp.m_configs.colors.current);
	END_SHOW_LYRIC();
}

// 刷新并生效配置
void RefreshLyricSetting()
{
	GtkWidget *pLyricWnd = theApp.m_LyricWnd.pThis;
	gtk_window_set_opacity(GTK_WINDOW(pLyricWnd), 1 - theApp.m_configs.iOpacity / 100.0);
	gtk_window_set_decorated(GTK_WINDOW(pLyricWnd), theApp.m_configs.bShowBroad);
	//ShowLyric();
}

void on_MenuAbout_activate(GtkWidget* wideget, gpointer user_data)
{
	theApp.About(GTK_WINDOW(user_data));
}

void on_MenuEditLyric_activate(GtkWidget* wideget, gpointer user_data)
{
	this.m_EditLyricDlg.EditLyric();
}

void on_MenuReDownLoad_activate(GtkWidget* wideget, gpointer user_data)
{
	SongInfo info;
	if (theApp.m_player.GetSongInfo(&info))
	{
		gchar szLrcFile[MAX_PATH] =
		{ 0 };
		sprintf(szLrcFile, "%s/%s/%s.lyric", theApp.m_configs.szLyricPath,
				info.szArtist, info.szTitle);
		strcpy(info.szLyricFileName, szLrcFile);
		SearchLyric(info, FALSE, theApp.m_configs.nSearchAppIndex, TRUE);
	}
}

void ChangeLyricTime(int iAdd)
{
	GList *list= this.m_ListCurrLyric;
	if (!list)return;
	this.m_bLyricChanging = TRUE;
	while (list)
	{
		LyricItem *item = (LyricItem *) list->data;
		item->iTime += iAdd;
		list = g_list_next(list);
	}
	this.m_bLyricChanging = FALSE;
	this.m_bLyricChanged = TRUE;
}

void on_MenuUpTime_activate(GtkWidget* wideget, gpointer user_data)
{
	ChangeLyricTime(500);
}

void on_MenuDownTime_activate(GtkWidget* wideget, gpointer user_data)
{
	ChangeLyricTime(-500);
}
void on_MenuShowBroad_toggled(GtkCheckMenuItem *checkmenuitem, gpointer user_data)
{
	GtkWidget *pLyricWnd = theApp.m_LyricWnd.pThis;
	gtk_window_set_decorated(GTK_WINDOW(pLyricWnd), checkmenuitem->active);
	theApp.m_configs.bShowBroad = checkmenuitem->active;
	theApp.UpdataSetting();
}
void on_MenuMouseScroll_toggled(GtkCheckMenuItem *checkmenuitem, gpointer user_data)
{
	this.m_bScrollMouseChange = !this.m_bScrollMouseChange; 
}
void on_MenuConfig_activate(GtkWidget* wideget, gpointer user_data)
{
	GladeXML *xml = glade_xml_new(CONFIG_GLADE_FILE, NULL, NULL);
	gtk_widget_show(ConfigDlgInit(xml));
}
gboolean on_ShowLyric_scroll_event(GtkWidget *widget, GdkEventScroll *event, gpointer user_data)
{
	if (event->type != GDK_SCROLL || !this.m_bScrollMouseChange)return FALSE;
	
	switch (event->direction)
	{
	case GDK_SCROLL_UP:
	case GDK_SCROLL_LEFT:
		ChangeLyricTime(1000);
		break;
	case GDK_SCROLL_DOWN:
	case GDK_SCROLL_RIGHT:
		ChangeLyricTime(-1000);
		break;
	}
	return FALSE;
}
gboolean on_ShowLyric_motion_notify_event(GtkWidget *widget, GdkEventMotion *event, gpointer user_data)
{
	return FALSE;
}

gboolean on_ShowLyric_button_press_event(GtkWidget *widget, GdkEventButton *event,
		gpointer user_data)
{
	if (event->type == GDK_BUTTON_PRESS)
	{
		if (event->button == 1)
		{
			gtk_window_begin_move_drag(GTK_WINDOW(gtk_widget_get_toplevel(widget)),
										event->button,
										event->x_root,
										event->y_root,
										event->time);
		}
	}


	if (event->button == 3)
	{
		GtkWidget *pLyricWnd = theApp.m_LyricWnd.pThis;
		GtkWidget *window = glade_xml_get_widget(theApp.m_xml, "LyricMenu");
		GtkCheckMenuItem *pMenuMouseScroll = (GtkCheckMenuItem*)glade_xml_get_widget(theApp.m_xml, "MenuMouseScroll");
		GtkCheckMenuItem *pMenuShowBroad = (GtkCheckMenuItem*)glade_xml_get_widget(theApp.m_xml, "MenuShowBroad");
		GtkCheckMenuItem *pMenuShowOSD = (GtkCheckMenuItem*)glade_xml_get_widget(theApp.m_xml, "MenuShowOSD");
		GtkCheckMenuItem *pMenuKaLaOK = (GtkCheckMenuItem*)glade_xml_get_widget(theApp.m_xml, "MenuKaLaOK");
		pMenuMouseScroll->active = this.m_bScrollMouseChange;
		pMenuShowBroad->active = gtk_window_get_decorated(GTK_WINDOW(pLyricWnd));
		pMenuShowOSD->active =theApp.m_configs.bShowOSDLyric;
		pMenuKaLaOK->active = theApp.m_configs.bIsKaLaOK;
		gtk_menu_popup(GTK_MENU(window), NULL, NULL, NULL, NULL, event->button,
				event->time);
		return TRUE;
	}
	return FALSE;
}

void on_ShowLyric_window_state_event(gpointer data)
{
	GtkWidget *window=this.pThis;
	int istate = gdk_window_get_state(GDK_WINDOW(window->window));

	gtk_window_set_skip_taskbar_hint(GTK_WINDOW(window), TRUE);
	gtk_window_set_skip_pager_hint(GTK_WINDOW(window), TRUE);
	switch (istate)
	{
	case GDK_WINDOW_STATE_ICONIFIED:
		gtk_window_set_skip_taskbar_hint(GTK_WINDOW(window), FALSE);
		gtk_window_set_skip_pager_hint(GTK_WINDOW(window), FALSE);
		//LyricDebug("GDK_WINDOW_STATE_ICONIFIED:the window is minimized.\n");
		break;
	case GDK_WINDOW_STATE_WITHDRAWN:
		//LyricDebug("GDK_WINDOW_STATE_WITHDRAWN:the window is not shown.\n");
		break;
	case GDK_WINDOW_STATE_MAXIMIZED:
		//LyricDebug("GDK_WINDOW_STATE_MAXIMIZED:the window is maximized.\n");
		break;
	case GDK_WINDOW_STATE_STICKY:
		//LyricDebug("GDK_WINDOW_STATE_STICKY:the window is sticky.\n");
		break;
	case GDK_WINDOW_STATE_FULLSCREEN:
		//LyricDebug("GDK_WINDOW_STATE_FULLSCREEN:the window is maximized without decorations.\n");
		break;
	case GDK_WINDOW_STATE_ABOVE:
		//LyricDebug("GDK_WINDOW_STATE_ABOVE:the window is kept above other windows. \n");
		break;
	case GDK_WINDOW_STATE_BELOW:
		//LyricDebug("GDK_WINDOW_STATE_BELOW:the window is kept below other windows. \n");
		break;
		/*
		 default:
		 //LyricDebug("unknow state(%d)\n", istate);
		 gtk_window_set_skip_taskbar_hint (GTK_WINDOW (window), FALSE);
		 gtk_window_set_skip_pager_hint (GTK_WINDOW (window), FALSE);
		 break;
		 */
	}
}

gboolean on_ShowLyric_delete_event(GtkWidget *widget, GdkEvent *event,
		gpointer user_data)
{
	// 将关闭事件改成最小化
	gtk_window_iconify(GTK_WINDOW(user_data));
	// 如果返回FALSE，GTK将发出"destroy"信号;
	// 如果返回TRUE， 则不让该窗口关闭
	return TRUE;
}

void on_MenuShowOSD_toggled(GtkCheckMenuItem *checkmenuitem, gpointer user_data)
{
	// 显示OSD歌词
	theApp.m_configs.bShowOSDLyric = checkmenuitem->active;
	if (theApp.m_configs.bShowOSDLyric == FALSE)
	{
		if (system("gnome-osd-client -f \"<message id='ShowLyric' hide_timeout='0'></message>\"") < 0)
		{
			LyricLog("Exec gnome-osd-client failed!");
		}
	}
	theApp.UpdataSetting();
}

void on_MenuKaLaOK_toggled(GtkCheckMenuItem *checkmenuitem, gpointer user_data)
{
	// 显示OSD歌词
	theApp.m_configs.bIsKaLaOK = checkmenuitem->active;
	LyricDebug("theApp.m_configs.bIsKaLaOK=%d", theApp.m_configs.bIsKaLaOK);
	theApp.UpdataSetting();
}

void on_MenuManualDownLoad_activate(GtkWidget* wideget, gpointer user_data)
{
	// 手动下载
	SongInfo info;
	if (theApp.m_player.GetSongInfo(&info))
	{
		GladeXML* xml = glade_xml_new(SEL_LYRIC_GLADE_FILE, NULL, NULL);
		ManualDownloadDlgInit(xml, info);
		GtkWidget * title = glade_xml_get_widget(xml, "entryTitleName");
		GtkWidget * artist = glade_xml_get_widget(xml, "entryArtistName");
		gtk_entry_set_text(GTK_ENTRY(title), info.szTitle);
		gtk_entry_set_text(GTK_ENTRY(artist), info.szArtist);

		gint nCount = theApp.m_player.GetSearchAppCount();
		gint nIndex = 0;
		AppInfo info = {0};
		for (nIndex == 0; nIndex < nCount; nIndex++)
		{
			theApp.m_player.GetSearchApp(nIndex, &info);
			gtk_combo_box_append_text(GTK_COMBO_BOX(glade_xml_get_widget(xml, "cbSearchApp")), info.szName);
		}
		gtk_combo_box_set_active(GTK_COMBO_BOX(glade_xml_get_widget(xml, "cbSearchApp")), theApp.m_configs.nSearchAppIndex);

		GtkWidget* pManualDownloadDlg = glade_xml_get_widget(xml, "ManualDownLoadDlg");
		gtk_widget_show(GTK_WIDGET(pManualDownloadDlg));
	}

}
